package com.wash.shoes.controller.app;

import com.aliyun.oss.common.utils.BinaryUtil;
import com.aliyun.sts20150401.Client;
import com.aliyun.sts20150401.models.AssumeRoleRequest;
import com.aliyun.sts20150401.models.AssumeRoleResponse;
import com.aliyun.sts20150401.models.AssumeRoleResponseBody;
import com.aliyun.teautil.models.RuntimeOptions;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.ruoyi.common.core.domain.R;
import com.wash.shoes.oss.ConstantProperties;
import com.wash.shoes.util.RAMGenerateSignature;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.codec.binary.Base64;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.time.Instant;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Log4j2
@Api(tags = {"APP-签名"})
@RestController
@RequestMapping("/mobile-api/sign")
public class VxAController {

    @Autowired
    RedissonClient redissonClient;

    @Autowired
    private Client stsClient;

    /**
     * 使用环境变量中的AK获取临时访问凭证，计算签名信息，返回小程序端。
     *
     * @return
     * @throws JsonProcessingException
     */
    @ApiOperation("签名")
    @GetMapping("/generateSignature")
    public R<Map> generateSignature() throws JsonProcessingException {

        AssumeRoleRequest assumeRoleRequest = new AssumeRoleRequest()
                //有晓时间为一个小时
                .setDurationSeconds(3600L)
                // 将<YOUR_ROLE_SESSION_NAME>设置为自定义的会话名称，例如 my-website-server。
                .setRoleSessionName("ramosstest")
                // 将<YOUR_ROLE_ARN>替换为拥有上传文件到指定OSS Bucket权限的RAM角色的ARN，可以在 RAM 角色详情中获得角色 ARN。
                .setRoleArn("acs:ram::1849398496984852:role/ramosstest");
        RuntimeOptions runtime = new RuntimeOptions();
        try {
            AssumeRoleResponse response = stsClient.assumeRoleWithOptions(assumeRoleRequest, runtime);
            AssumeRoleResponseBody.AssumeRoleResponseBodyCredentials credentials = response.body.credentials;

            //格式化请求日期
            long now = System.currentTimeMillis() / 1000;
            ZonedDateTime dtObj = ZonedDateTime.ofInstant(Instant.ofEpochSecond(now), ZoneId.of("UTC"));
            ZonedDateTime dtObjPlus3h = dtObj.plusHours(3);
            //请求时间
            DateTimeFormatter dtObj1Formatter = DateTimeFormatter.ofPattern("yyyyMMdd'T'HHmmss'Z'");
            String dtObj1 = dtObj.format(dtObj1Formatter);
            //请求日期
            DateTimeFormatter dtObj2Formatter = DateTimeFormatter.ofPattern("yyyyMMdd");
            String dtObj2 = dtObj.format(dtObj2Formatter);
            //请求过期时间
            DateTimeFormatter expirationTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
            String expirationTime = dtObjPlus3h.format(expirationTimeFormatter);

            String STSaccessKeyId = credentials.accessKeyId;
            String STSsecretAccessKey = credentials.accessKeySecret;
            String regionId = "cn-heyuan";
            String securityToken = credentials.getSecurityToken();
            // 创建policy
            ObjectMapper mapper = new ObjectMapper();

            Map<String, Object> policy = new HashMap<>();
            policy.put("expiration", expirationTime);

            List<Object> conditions = new ArrayList<>();

            Map<String, String> bucketCondition = new HashMap<>();
            bucketCondition.put("bucket", ConstantProperties.BUCKETNAME);  //请替换为目标bucket名称
            conditions.add(bucketCondition);

            Map<String, String> signatureVersionCondition = new HashMap<>();
            signatureVersionCondition.put("x-oss-signature-version", "OSS4-HMAC-SHA256");
            conditions.add(signatureVersionCondition);

            Map<String, String> credentialCondition = new HashMap<>();
            credentialCondition.put("x-oss-credential", STSaccessKeyId + "/" + dtObj2 + "/" + regionId + "/oss/aliyun_v4_request"); // 替换为实际的 access key id
            conditions.add(credentialCondition);

            Map<String, String> token = new HashMap<>();
            token.put("x-oss-security-token", securityToken);
            conditions.add(token);

            Map<String, String> dateCondition = new HashMap<>();
            dateCondition.put("x-oss-date", dtObj1);
            conditions.add(dateCondition);

            policy.put("conditions", conditions);
            String jsonPolicy = mapper.writeValueAsString(policy);
            //构造待签名字符串（StringToSign）
            String stringToSign = new String(Base64.encodeBase64(jsonPolicy.getBytes()));

            byte[] dateKey = hmacsha256(("aliyun_v4" + STSsecretAccessKey).getBytes(), dtObj2);
            byte[] dateRegionKey = hmacsha256(dateKey, regionId);
            byte[] dateRegionServiceKey = hmacsha256(dateRegionKey, "oss");
            byte[] signingKey = hmacsha256(dateRegionServiceKey, "aliyun_v4_request");
            //计算Signature
            byte[] result = hmacsha256(signingKey, stringToSign);
            String signature = BinaryUtil.toHex(result);

            Map<String, String> messageMap = new HashMap<>();
            messageMap.put("security_token", securityToken);
            messageMap.put("signature", signature);
            messageMap.put("x_oss_date", dtObj1);
            messageMap.put("x_oss_credential", STSaccessKeyId + "/" + dtObj2 + "/" + regionId + "/oss/aliyun_v4_request");
            messageMap.put("x_oss_signature_version", "OSS4-HMAC-SHA256");
            messageMap.put("policy", stringToSign);

            return R.ok(messageMap);
        } catch (Exception error) {
            log.error(error);
            return R.fail(error.getMessage());
        }
    }

    public static byte[] hmacsha256(byte[] key, String data) {
        try {
            SecretKeySpec secretKeySpec = new SecretKeySpec(key, "HmacSHA256");
            Mac mac = Mac.getInstance("HmacSHA256");
            mac.init(secretKeySpec);
            return mac.doFinal(data.getBytes());
        } catch (Exception e) {
            throw new RuntimeException("Failed to calculate HMAC-SHA256", e);
        }
    }

    /**
     * 使用环境变量中的AK获取临时访问凭证，计算签名信息，返回小程序端。
     *
     * @return
     * @throws JsonProcessingException
     */
    @ApiOperation("签名-新的签名")
    @GetMapping("/generateSignature2")
    public R<Object> generate_signature2() throws JsonProcessingException {
        RAMGenerateSignature ramGenerateSignature = new RAMGenerateSignature();
        return R.ok(ramGenerateSignature.getSignature());
    }

}
